package com.heima.comment.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.aliyun.GreenTextScan;
import com.heima.comment.service.CommentHotService;
import com.heima.comment.service.CommentService;
import com.heima.common.constants.article.HotArticleConstants;
import com.heima.common.exception.CustException;
import com.heima.feigns.UserFeign;
import com.heima.model.comment.dtos.CommentDTO;
import com.heima.model.comment.dtos.CommentLikeDTO;
import com.heima.model.comment.dtos.CommentSaveDTO;
import com.heima.model.comment.pojos.ApComment;
import com.heima.model.comment.pojos.ApCommentLike;
import com.heima.model.comment.vos.ApCommentVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.mess.app.NewBehaviorDTO;
import com.heima.model.threadlocal.AppThreadLocalUtils;
import com.heima.model.user.pojos.ApUser;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;


@Service
@Slf4j
public class CommentServiceImpl implements CommentService {

    @Autowired
    private GreenTextScan greenTextScan;

    @Autowired
    private UserFeign userFeign;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private CommentHotService commentHotService;


    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RabbitTemplate rabbitTemplate;


    /**
     * 保存评论
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult saveComment(CommentSaveDTO dto) {
        //1. 校验参数
        //   校验是否登录
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        //   校验文章id   校验内容不为空  校验内容长度不能大于140个字符 (validated校验)

        //2. 阿里云校验评论内容是否违规
        try {
            Map resultMap = greenTextScan.greenTextScan(dto.getContent());
            //       (简单:  此步不做      普通: 阿里云检测有问题提示      高级:  有问题不报异常，替换为**)
            //3. 远程查询当前登陆用户信息
            String suggestion = resultMap.get("suggestion").toString();
            if (!"pass".equals(suggestion)) {
                Object filteredContent = resultMap.get("filteredContent");
                if (filteredContent != null) {
                    String str = filteredContent.toString();
                    dto.setContent(str);
                }
            }


            //3. 远程查询当前登陆用户信息
            ResponseResult<ApUser> data = userFeign.findUserById(user.getId());
            if (data.getCode() != 0) {
                CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR);
            }
            ApUser apUser = data.getData();
//            //远程调用获取文章信息
//            ResponseResult<ApArticle> article = articleFeign.findArticle(dto.getArticleId());
//            if (article.getCode() != 0) {
//                CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR);
//            }
//            ApArticle apArticle = article.getData();


            //4. 创建评论信息，并保存到mongo
            ApComment apComment = new ApComment();
            apComment.setAuthorId(apUser.getId());   //作者
            apComment.setAuthorName(apUser.getName());  //作者名字
            apComment.setArticleId(dto.getArticleId());  //文章id
            apComment.setContent(dto.getContent());
            apComment.setLikes(0);   //点赞数量
            apComment.setReply(0);  //回复数量
            apComment.setImage(user.getImage());
            // TODO   热点评论
            apComment.setFlag((short) 0);    //文章标记
            apComment.setCreatedTime(new Date());   //创建时间

            //保存到MongoDB
            mongoTemplate.save(apComment);


            //发送消息到队列
            NewBehaviorDTO mess = new NewBehaviorDTO();
            mess.setType(NewBehaviorDTO.BehaviorType.COMMENT);
            mess.setAdd(1);
            mess.setArticleId(dto.getArticleId());
            //发送消息到队列
            rabbitTemplate.convertAndSend(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_QUEUE, JSON.toJSONString(mess));
            log.info("点赞行为 发送消息 ==>{}",JSON.toJSONString(mess));




            return ResponseResult.okResult(apComment);
        } catch (Exception e) {
            e.printStackTrace();
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR);
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
        }
    }


    /**
     * 点赞评论
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult like(CommentLikeDTO dto) {
        //1. 参数校验
        //   评论id不能为空  operation必须为 0  或  1
        //2. 根据评论id查询评论数据， 为返回错误信息
        Query query = Query.query(Criteria.where("id").is(dto.getCommentId()));
        ApComment apComment = mongoTemplate.findOne(query, ApComment.class);
        if (apComment == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "该评论已经不存在");
        }


        //获取当前用户
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }

        //添加分布式锁
        RLock likes_lock = redissonClient.getLock("likes_lock");
        likes_lock.lock();


        try {
            //3. 如果是点赞操作 判断是否已经点赞   0 点赞    1 取消
            Query query1 = Query.query(Criteria.where("commentId").is(dto.getCommentId()));
            ApCommentLike commentLike = mongoTemplate.findOne(query1, ApCommentLike.class);


            if (dto.getOperation() == 0) {
                //   点过赞提示 请勿重复点赞
                if (commentLike == null) {
                    //   未点过赞   保存点赞信息到mongo
                    ApCommentLike apCommentLike = new ApCommentLike();
                    apCommentLike.setAuthorId(user.getId());
                    apCommentLike.setCommentId(apComment.getId());
                    apCommentLike.setOperation((short) 0);

                    //插入数据
                    commentLike = mongoTemplate.save(apCommentLike);
                }else {
                    CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW,"不可以重复点赞");
                }
                //   并修改评论信息的点赞数量( + 1)
                apComment.setLikes(apComment.getLikes() + 1);
                apComment.setUpdatedTime(new Date());
                if (apComment.getLikes() >= 10 && apComment.getFlag() == 0){
                    commentHotService.hotCommentExecutor(apComment);
                }
                //修改评论
                mongoTemplate.save(apComment);


                //修改点赞表
                commentLike.setOperation((short) 0);
                mongoTemplate.save(commentLike);


    //            if (commentLike.getOperation() == 0){
    //                CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW);
    //            }


                Map<String, Object> map = new HashMap();
                map.put("likes", apComment.getLikes());
                return ResponseResult.okResult(map);
            }


            //4. 如果是取消点赞操作
            //   删除点赞信息
            //   并修改评论信息的点赞数量( - 1) , 要判断下别减成负数
            Integer likes = apComment.getLikes();
            likes = likes - 1;
            if (likes - 1 < 0) {
                likes = 0;
            }
            //修改评论表
            apComment.setLikes(likes);
            mongoTemplate.save(apComment);


//        //修改点赞表
//        commentLike.setOperation((short) 1);
//        mongoTemplate.save(commentLike);
            mongoTemplate.remove(commentLike);
        } finally {
            //释放锁
            likes_lock.unlock();
        }

        //5. 返回结果时，需要返回点赞点赞数量  返回的key要求必须是:  likes
        Map<String, Object> map = new HashMap();
        map.put("likes", apComment.getLikes());
        //返回结果
        return ResponseResult.okResult(map);

    }


    /**
     * 查询评论列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findByArticleId(CommentDTO dto) {
        //1. 参数校验
        //   校验文章id
        //   校验size
        ;
        if (dto.getSize()== null) {
            dto.setSize(10);
        }

        if (dto.getIndex() == null) {
            dto.setIndex((short) 0);
        }


        //2. 根据条件查询评论列表
        //   (文章id  , 创建时间 小于最小时间 , 截取size条记录 , 创建时间降序)
        Long articleId = dto.getArticleId();
        //查询条件
        Query query = Query.query(Criteria.where("articleId").is(articleId));
        //分页参数
        PageRequest pageRequest = PageRequest.of(dto.getIndex() - 1, dto.getSize());
        query.with(pageRequest);
        //最小时间
//        Date minDate = dto.getMinDate();
//        if (minDate == null){
//            minDate = new Date();
//        }
        //排序
        Sort sort = Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);// 排序

        List<ApComment> apComments = mongoTemplate.find(query, ApComment.class);


        List<ApComment> apCommentList = null;
        if(dto.getIndex().intValue() == 1){ // 判断当前是否是第一页评论
            // 先查询热点评论集合  （最多5条） (条件: flag=1, 文章id, 点赞降序)
            Query query2 = Query.query(Criteria.where("articleId").is(dto.getArticleId())
                    .and("flag").is((short)1)).limit(5);
            Sort sort2 = Sort.by(Sort.Direction.DESC,"likes");
            query2.with(sort2);// 排序
            apCommentList = mongoTemplate.find(query2, ApComment.class);

            
            // 新size = size - 热评数量
            dto.setSize(dto.getSize() - apCommentList.size());

            // 查询第一页剩余普通评论 (条件: 文章id, flag=0, 时间降序, limit:新size)
            Query query3 = Query.query(Criteria.where("articleId").is(dto.getArticleId())
                    .and("flag").is((short)0)).limit(dto.getSize());
            Sort sort3 = Sort.by(Sort.Direction.DESC,"createdTime");
            query3.with(sort3);// 排序
            List<ApComment> newAComments = mongoTemplate.find(query3, ApComment.class);

            // 合并 热点评论  普通评论   热点list.addAll(普通list)
            apCommentList.addAll(newAComments);


        }else {
            // 不是第一页直接查询普通评论
            // (条件: 文章id,flag=0,createdTime小于最小时间,时间降序,limit:size)
            Query query3 = Query.query(Criteria.where("articleId").is(dto.getArticleId())
                    .and("flag").is((short)0)).limit(dto.getSize());
            Sort sort3 = Sort.by(Sort.Direction.DESC,"createdTime");
            query.with(sort3);// 排序
            apCommentList = mongoTemplate.find(query3, ApComment.class);
        }




        //3. 判断当前用户是否登录
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null) {
            //4. 如果未登录直接返回评论列表
            return ResponseResult.okResult(apComments);
        }

        //5. 如果登录了 需要检查在当前评论列表中 哪些评论登陆人点赞过
        //   (将所有ApComment 转成 ApCommentVO , 点过赞的operation设置为0)
        //   推荐实现:
        //   5.1 根据当前列表中评论id  和  登录人id 查询评论点赞表，得到点赞数据
        //                 commentId  in    评论id列表   authorId = 登录人id

        //获取当前登录人的id
        Integer userId = user.getId();
        List<ApCommentLike> likeList = new ArrayList<>();
        //查询有登录人点赞的评论
        for (ApComment apComment : apCommentList) {
            //获取每一条评论的id
            String id = apComment.getId();
            Query query1 = Query.query(Criteria.where("commentId").is(id)
                    .and("authorId").is(userId));
            ApCommentLike apCommentLike = mongoTemplate.findOne(query1, ApCommentLike.class);
            if (apCommentLike != null && apCommentLike.getOperation() == 0) {
                likeList.add(apCommentLike);
            }
        }

        if (CollectionUtils.isEmpty(likeList)) {
            return ResponseResult.okResult(apComments);
        }

//        //将每一个apComment 转化成 apCommentVo
//        apCommentVo.setId(apComment.getId());
//        apCommentVo.setAuthorId(apComment.getAuthorId());
//        apCommentVo.setAuthorName(apComment.getAuthorName());
//        apCommentVo.setArticleId(apComment.getArticleId());
//        apCommentVo.setType(apComment.getType());
//        apCommentVo.setChannelId(apComment.getChannelId());
//        apCommentVo.setContent(apComment.getContent());
//        apCommentVo.setImage(apComment.getImage());
//        apCommentVo.setLikes(apComment.getLikes());
//        apCommentVo.setReply(apComment.getReply());
//        apCommentVo.setFlag(apComment.getFlag());
//        apCommentVo.setLongitude(apComment.getLongitude());
//        apCommentVo.setLatitude(apComment.getLatitude());
//        apCommentVo.setAddress(apComment.getAddress());
//        apCommentVo.setOrd(apComment.getOrd());
//        apCommentVo.setCreatedTime(apComment.getCreatedTime());
//        apCommentVo.setUpdatedTime(apComment.getUpdatedTime());


        //   5.2 遍历评论列表
        //             将每一个评论  ApComment 转成 ApCommentVO
        //             其中  如果当前评论id在点赞记录中存在  设置operation字段为0  不存在不用做任何处理
        //创建一个集合 存储返回的数据
        boolean fale = false;
        List<ApCommentVo> apVoComment = new ArrayList<>();
        for (ApComment apComment : apCommentList) {
            ApCommentVo apCommentVo = new ApCommentVo();
            //将每一个apComment 转化成 apCommentVo
            BeanUtils.copyProperties(apComment, apCommentVo);
            //判断数据是否被点赞
            for (ApCommentLike apCommentLike : likeList) {
                if (apCommentLike.getCommentId().equals(apComment.getId())) {
                    //说明这个评论被点赞了
                    apCommentVo.setOperation((short) 0);
                    apVoComment.add(apCommentVo);
                    fale = true;
                    break;
                }
                fale = false;
            }
            if (!fale) {
                apVoComment.add(apCommentVo);
            }
        }
        return ResponseResult.okResult(apVoComment);
    }
}
